The Xen checksum offload feature attempts to insert a TCP/UDP
authorkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Sat, 22 Apr 2006 09:41:53 +0000 (10:41 +0100)
committerkaf24@firebug.cl.cam.ac.uk <kaf24@firebug.cl.cam.ac.uk>
Sat, 22 Apr 2006 09:41:53 +0000 (10:41 +0100)
checksums into already encrypted packets (esp4) in dom0.  Obviously,
it is not possible to insert a checksum into an already encrypted
packet, so this patch inserts the checksum prior to encrypting
packets in net/ipv4/xfrm4_output.c.

To do this cleanly, the TCP/UDP header pointers need to be pointed to
the correct spot, so this functionality has been abstracted into a new
function.

This patch fixes bug 143 (verified by Jim Dykman).  Earlier version
verified by Jon McCune.

Signed-off-by: James Dykman <dykman@us.ibm.com>
Signed-off-by: Jon Mason <jdmason@us.ibm.com>
linux-2.6-xen-sparse/net/core/dev.c
patches/linux-2.6.16/net-csum.patch

index e526fccc2f9d326c10a096f81c9e4509940e55b2..492fb7c80090e0b03c087acaa10d5540d4813e13 100644 (file)
@@ -1220,6 +1220,43 @@ int __skb_linearize(struct sk_buff *skb, gfp_t gfp_mask)
        }                                               \
 }
 
+#ifdef CONFIG_XEN
+inline int skb_checksum_setup(struct sk_buff *skb)
+{
+       if (skb->proto_csum_blank) {
+               if (skb->protocol != htons(ETH_P_IP))
+                       goto out;
+               skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl;
+               if (skb->h.raw >= skb->tail)
+                       goto out;
+               switch (skb->nh.iph->protocol) {
+               case IPPROTO_TCP:
+                       skb->csum = offsetof(struct tcphdr, check);
+                       break;
+               case IPPROTO_UDP:
+                       skb->csum = offsetof(struct udphdr, check);
+                       break;
+               default:
+                       if (net_ratelimit())
+                               printk(KERN_ERR "Attempting to checksum a non-"
+                                      "TCP/UDP packet, dropping a protocol"
+                                      " %d packet", skb->nh.iph->protocol);
+                       goto out;
+               }
+               if ((skb->h.raw + skb->csum + 2) > skb->tail)
+                       goto out;
+               skb->ip_summed = CHECKSUM_HW;
+               skb->proto_csum_blank = 0;
+       }
+       return 0;
+out:
+       return -EPROTO;
+}
+#else
+inline int skb_checksum_setup(struct sk_buff *skb) {}
+#endif
+
+
 /**
  *     dev_queue_xmit - transmit a buffer
  *     @skb: buffer to transmit
@@ -1266,38 +1303,12 @@ int dev_queue_xmit(struct sk_buff *skb)
            __skb_linearize(skb, GFP_ATOMIC))
                goto out_kfree_skb;
 
-#ifdef CONFIG_XEN
-       /* If a checksum-deferred packet is forwarded to a device that needs a
-        * checksum, correct the pointers and force checksumming.
-        */
-       if (skb->proto_csum_blank) {
-               if (skb->protocol != htons(ETH_P_IP))
-                       goto out_kfree_skb;
-               skb->h.raw = (unsigned char *)skb->nh.iph + 4*skb->nh.iph->ihl;
-               if (skb->h.raw >= skb->tail)
-                       goto out_kfree_skb;
-               switch (skb->nh.iph->protocol) {
-               case IPPROTO_TCP:
-                       skb->csum = offsetof(struct tcphdr, check);
-                       break;
-               case IPPROTO_UDP:
-                       skb->csum = offsetof(struct udphdr, check);
-                       break;
-               default:
-                       if (net_ratelimit())
-                               printk(KERN_ERR "Attempting to checksum a non-"
-                                      "TCP/UDP packet, dropping a protocol"
-                                      " %d packet", skb->nh.iph->protocol);
-                       rc = -EPROTO;
-                       goto out_kfree_skb;
-               }
-               if ((skb->h.raw + skb->csum + 2) > skb->tail)
-                       goto out_kfree_skb;
-               skb->ip_summed = CHECKSUM_HW;
-               skb->proto_csum_blank = 0;
-       }
-#endif
-
+       /* If a checksum-deferred packet is forwarded to a device that needs a
+        * checksum, correct the pointers and force checksumming.
+        */
+       if(skb_checksum_setup(skb))
+               goto out_kfree_skb;
+  
        /* If packet is not checksummed and device does not support
         * checksumming for this protocol, complete checksumming here.
         */
@@ -3351,6 +3362,7 @@ EXPORT_SYMBOL(unregister_netdevice_notifier);
 EXPORT_SYMBOL(net_enable_timestamp);
 EXPORT_SYMBOL(net_disable_timestamp);
 EXPORT_SYMBOL(dev_get_flags);
+EXPORT_SYMBOL(skb_checksum_setup);
 
 #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
 EXPORT_SYMBOL(br_handle_frame_hook);
index d6ede6b258244f9b0ab07cb7e429ebe52ef5931e..6543dcc47bcfde24346f9d31f0cccfd999ffb7eb 100644 (file)
@@ -39,3 +39,26 @@ diff -pruN ../pristine-linux-2.6.16/net/ipv4/netfilter/ip_nat_proto_udp.c ./net/
        *portptr = newport;
        return 1;
  }
+diff -r 601fa226a761 net/ipv4/xfrm4_output.c
+--- a/net/ipv4/xfrm4_output.c  Wed Apr 19 18:52:30 2006
++++ b/net/ipv4/xfrm4_output.c  Thu Apr 20 15:49:40 2006
+@@ -16,6 +16,8 @@
+ #include <net/ip.h>
+ #include <net/xfrm.h>
+ #include <net/icmp.h>
++
++extern int skb_checksum_setup(struct sk_buff *skb);
+ /* Add encapsulation header.
+  *
+@@ -103,6 +105,10 @@
+       struct xfrm_state *x = dst->xfrm;
+       int err;
+       
++      err = skb_checksum_setup(skb);
++      if (err)
++              goto error_nolock;
++
+       if (skb->ip_summed == CHECKSUM_HW) {
+               err = skb_checksum_help(skb, 0);
+               if (err)